package sidecar

import (
	"io"
	su "lqq/sidecar/utils"
	"net"

	CMap "github.com/orcaman/concurrent-map"
)

type serverConn struct {
	ss       *serverService
	c        io.ReadWriteCloser
	CLIENTID string
	canUse   bool
	reqStore CMap.ConcurrentMap
}

type serverService struct {
	addr        string
	requestChan chan *requestMsg
	respChan    chan *requestMsg
	connStore   CMap.ConcurrentMap
}

func (ss *serverService) listenData() error {
	listen, err := net.Listen("TCP", ss.addr)
	if err != nil {
		return err
	}
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil {
			return err
		}
		cc := &serverConn{
			ss: ss,
			c:  conn,
		}
		go cc.monitorRead()
	}
}

func (ss *serverService) writeResponseToClient(req *requestMsg) {
	ss.respChan <- req
}
func (ss *serverService) monitorRespChan() {
	for {
		select {
		case req := <-ss.respChan:
			conn, ok := ss.connStore.Get(req.respHeader.CLIENTID)
			if !ok {
				logger.error("can not find server connection")
				continue
			}
			w := conn.(*serverConn)
			err := w.writeResp(req)
			if err != nil {
				logger.error(err.Error())
			}
		}
	}
}

func (sc *serverConn) writeResp(req *requestMsg) error {
	b := req.toRequestBytes()
	return su.WriteDataToConn(sc.c, b)
}
func (sc *serverConn) monitorRead() {
	defer sc.c.Close()
	firstRead := true
	for {
		b, err := su.ReadDataFromConn(sc.c)
		if err != nil {
			logger.error(err.Error())
			sc.canUse = false
			sc.c.Close()
			sc.ss.connStore.Remove(sc.CLIENTID)
			break
		}

		hLen := su.ComputeLen(b[:4])
		if len(b) < hLen+4 {
			logger.error("len(b) < hLen+4")
			continue
		}
		headBytes := b[4 : hLen+4]
		h := su.ReadPropToMap(headBytes)
		head := &RequestHeader{}
		head.REQID = h["REQID"]
		if len(head.REQID) == 0 {
			logger.error("reqid can not be empty")
			continue
		}
		head.TRACEID = h["TRACEID"]
		head.CLIENTID = h["CLIENTID"]
		head.CallURL = h["CallURL"]
		head.ServiceName = h["ServiceName"]
		head.HashStr = h["HashStr"]
		if firstRead {
			sc.CLIENTID = head.CLIENTID
			if len(sc.CLIENTID) == 0 {
				logger.error("clientid can not be empty")
				break
			}
			sc.ss.connStore.Set(sc.CLIENTID, sc)
			continue
		}
		reqMsg := &requestMsg{}
		reqMsg.reqHeader = head
		reqMsg.reqData = b[hLen+4:]
		reqMsg.reqHeaderBytes = headBytes
		if len(head.HashStr) > 0 {
			md5sub := su.CreateMd5HashWithLength(reqMsg.reqData, len(head.HashStr))
			if md5sub != head.HashStr {
				logger.error("md5sub!= head.HashStr")
				continue
			}
		}
		//sc.reqStore.Set(head.REQID, reqMsg)
		firstRead = false
		sc.ss.requestChan <- reqMsg
	}
}
